
#include "qyFileSystem.h"
#include "../lex/qyLex.h"
#include "qyFileFilter.h"

//-----------------------------------------------------------------------
void qyFormatPath( const qyString &orig, qyString &formated )
{
	qyTokenSep sep( "\\/" );
	qyTokenizer tokenizer( orig, sep );
	formated = "";
	for ( qyTokenIterator token = tokenizer.begin(); token != tokenizer.end(); ++token )
	{
		formated += (*token);
		formated += "/";
	}
}

qyString qyFormatPath( const qyString &orig )
{
	qyTokenSep sep( "\\/" );
	qyTokenizer tokenizer( orig, sep );
	qyString formated( "" );
	for ( qyTokenIterator token = tokenizer.begin(); token != tokenizer.end(); ++token )
	{
		formated += (*token);
		formated += "/";
	}
	return formated;
}

qyString qyFormatFilePath( const qyString &orig )
{
	qyTokenSep sep( "\\/" );
	qyTokenizer tokenizer( orig, sep );
	qyString formated( "" );
	qyTokenizer::iterator token = tokenizer.begin();
	formated += (*token);
	++token;
	for ( ; token != tokenizer.end(); ++token )
	{
		formated += "/";
		formated += (*token);
	}
	
	return formated;
}

//-----------------------------------------------------------------------
template<>	qyFileSystem *qySingleton<qyFileSystem>::m_sSingleton = NULL;

//-----------------------------------------------------------------------
qyFileSystem::qyFileSystem()
{
	m_commonFilter = new qyFileFilter;
}

//-----------------------------------------------------------------------
qyFileSystem::~qyFileSystem()
{
	delete m_commonFilter;
	RemoveAllRootPath();
	RemoveAllPackage();
}

//-----------------------------------------------------------------------
void qyFileSystem::AddRootPath( const qyString &path )
{
	m_paths.push_back( qyFormatPath( path ) );
}

//-----------------------------------------------------------------------
void qyFileSystem::RemoveRootPath( const qyString &path )
{
	qyString formatedPath = qyFormatPath( path );
	for ( PathList::iterator it = m_paths.begin(); it != m_paths.end(); ++it )
	{
		if ( (*it) == formatedPath )
		{
			m_paths.erase( it );
		}
	}
}

//-----------------------------------------------------------------------
const qyString & qyFileSystem::GetRootPath() const
{
	assert( m_paths.size() != 0 );
	return m_paths[0];
}

//-----------------------------------------------------------------------
qyFile * qyFileSystem::OpenReadFile( const qyString &filename, bool bUsingAbsolutePath )
{
	qyFile *file = new qyFile( filename );

	//
	// absolute path
	//
	if ( bUsingAbsolutePath )
	{
		if ( !m_commonFilter->LoadFileToMemory( filename, *file ) )
		{
			delete file;
			return NULL;
		}
		return file;
	}
    if ( m_commonFilter->LoadFileToMemory( filename, *file ) )
    {
        return file;
    }
	//
	// try in normal folder
	//
	PathList::iterator itPathEnd = m_paths.end();
	for ( PathList::iterator it = m_paths.begin(); it != itPathEnd; ++it )
	{
		if ( RequireFile( file, (*it) ) )
			return file;
	}

	//
	// try in package
	//
	PackageList::iterator itPkgEnd = m_packages.end();
	for ( PackageList::iterator it = m_packages.begin(); it != itPkgEnd; ++it )
	{
		qyZipPackage *package = (*it);
		if ( package->OpenReadFile( *file, filename ) )
		{
			return file;
		}
	}
	delete file;
	return NULL;
}

//-----------------------------------------------------------------------
bool qyFileSystem::RequireFile( qyFile *file, const qyString &rootPath )
{
#if defined(WIN32)
	return m_commonFilter->LoadFileToMemory( rootPath + file->GetFileName(), *file );
#else 
	return m_commonFilter->LoadFileToMemory( rootPath + file->GetFileName(), *file );
#endif
}

//-----------------------------------------------------------------------
qyZipPackage * qyFileSystem::AddPackage( const qyString &name )
{
	qyZipPackage *package = new qyZipPackage;
	PackageList::iterator end = m_packages.end();
	if ( !package->SetPackageFile( name ) )
	{
		delete package;
		return NULL;
	}
	m_packages.push_back( package );
	return package;
}

//-----------------------------------------------------------------------
bool qyFileSystem::RemovePackage( const qyString &name )
{
	qyString formatedPath = qyFormatPath( name );
	PackageList::iterator end = m_packages.end();
	for ( PackageList::iterator it = m_packages.begin(); it != end; ++it )
	{
		if ( (*it)->GetPackageFile() == formatedPath )
		{
			delete (*it);
			m_packages.erase( it );
			return true;
		}
	}
	return false;
}

//-----------------------------------------------------------------------
qyZipPackage * qyFileSystem::GetPackage( const qyString &name )
{
	qyString formatedPath = qyFormatPath( name );
	PackageList::iterator end = m_packages.end();
	for ( PackageList::iterator it = m_packages.begin(); it != end; ++it )
	{
		if ( (*it)->GetPackageFile() == formatedPath )
		{
			return (*it);
		}
	}
	return NULL;
}

//-----------------------------------------------------------------------
void qyFileSystem::RemoveAllRootPath()
{
	m_paths.clear();
}

//-----------------------------------------------------------------------
void qyFileSystem::RemoveAllPackage()
{
	PackageList::iterator end = m_packages.end();
	for ( PackageList::iterator it = m_packages.begin(); it != end; ++it )
	{
		qyZipPackage *pkg = (*it);
		delete pkg;
	}
	m_packages.clear();
}

//-----------------------------------------------------------------------
qyString qyFileSystem::GetRelatedPathFromFullPath( const qyString &path )
{
	assert( m_paths.size() != 0 );
	const qyString & rootPath = m_paths[0];
	qyString fullPath = qyFormatFilePath( path );
	
	int length = fullPath.length() - rootPath.length();
	char filebuffer[255];
	strcpy( filebuffer, fullPath.c_str()+rootPath.length() );
	//memcpy( filebuffer, fullPath.c_str()+rootPath.length(), length );
	//filebuffer[length+1] = '\0';
	return qyString( filebuffer );
}

//-----------------------------------------------------------------------
qyString qyFileSystem::GetFullPathFromRelatedPath( const qyString &path )
{
	const qyString &rootPath = m_paths[0];
	return rootPath + path;
}
